package com.katze.common.heart.server;

import com.katze.common.heart.HeartBeatHandle;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

public class HeartBeatServer {
    private static final Logger log = LoggerFactory.getLogger(HeartBeatServer.class);

    private final EventLoopGroup boss = new NioEventLoopGroup(1);
    private final EventLoopGroup worker = new NioEventLoopGroup(2);
    private final InetSocketAddress address;
    private final HeartBeatHandle handle;

    public HeartBeatServer(InetSocketAddress address, HeartBeatHandle handle){
        this.address = address;
        this.handle = handle;
    }

    public void initialization() throws InterruptedException {
        HeartBeatServer server = this;
        ServerBootstrap bootstrap = new ServerBootstrap().group(boss, worker).channel(NioServerSocketChannel.class);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast("decoder", new StringDecoder());
                pipeline.addLast("encoder", new StringEncoder());
                // IdleStateHandler 的 readerIdleTime 参数指定超过3秒还没收到客户端的连接，
                // 会触发 IdleStateEvent 事件并且交给下一个 handler 处理，
                // 下一个 handler 必须实现 userEventTriggered 方法处理对应事件
                pipeline.addLast(new IdleStateHandler(180, 0, 0));
                // 所以，HeartBeatServerHandler 必须要有实现 userEventTriggered 方法
                pipeline.addLast(new HeartBeatServerHandler(server));
            }
        });
        ChannelFuture future = bootstrap.bind(address).sync();
        if (future.isSuccess()) {
            log.info("Heart Beat Server ({}) Start!", address.toString());
        }
    }

    /**
     * 销毁
     */
    public void destroy() {
        worker.shutdownGracefully().syncUninterruptibly();
        boss.shutdownGracefully().syncUninterruptibly();
        log.info("Heart Beat Server Close!");
    }

    protected void active(String name, String address, String port){
        handle.changedStatus(name, address + ":" + port, 2);
    }

    protected void exit(String name, String address, String port){
        handle.changedStatus(name, address + ":" + port, 1);
    }

    protected String channel(String... message) {
        return handle.channel(message);
    }
}
